////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2009 Daniel F. Hanson
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
////////////////////////////////////////////////////////////////////////////////

using System;
using System.Collections;
using System.Collections.Generic;

namespace SilverLua.Runtime
{
   /// <summary>
   /// Represents the 'table' type from Lua. Stores key-value pairs of
   /// SilverLua Values. Any Value may be a key.
   /// </summary>
   public class Table : IEnumerable<KeyValuePair<Value, Value>>
   {
      private Dictionary<Value, Value> _values = new Dictionary<Value, Value>();

      /// <summary>
      /// Overridden to provide hash code for Table Values.
      /// </summary>
      /// <returns>Hash code of Table</returns>
      public override int GetHashCode()
      {
         return _values.GetHashCode();
      }
      
      /// <summary>
      /// Gets or sets the Table entry of the given key.
      /// </summary>
      /// <param name="key">Name of Table entry</param>
      /// <returns>The corresponding value, or Value.Nil if not found</returns>
      public Value this[Value key]
      {
         get
         {
            if (key == Value.Nil)
            {
               throw new ArgumentException("Cannot use Nil as a table key");
            }
            
            Value value;
            if (!_values.TryGetValue(key, out value))
            {
               value = new Value();
               _values.Add(key, value);
            }
            return value;
         }
         set
         {
            if (key == Value.Nil)
            {
               throw new ArgumentException("Cannot use Nil as a table key");
            }

            _values[key] = value;
         }
      }
      
      /// <summary>
      /// Gets the number of entries in the Table.
      /// </summary>
      public int Length
      {
         get { return _values.Count; }
      }
      
      internal Table Clone()
      {
         Table table = new Table();
         table._values = new Dictionary<Value, Value>();
         
         foreach (KeyValuePair<Value, Value> pair in _values)
         {
            table._values.Add(pair.Key, pair.Value.Clone());
         }
         
         return table;
      }
      
      public IEnumerator<KeyValuePair<Value, Value>> GetEnumerator()
      {
         return _values.GetEnumerator();
      }
      
      IEnumerator IEnumerable.GetEnumerator()
      {
         return GetEnumerator();
      }
      
      public Dictionary<Value, Value>.KeyCollection Keys { get { return _values.Keys; } }
   }
}
